package net.shambolica.ember.jinterface.wrappers.objects.patterns;

import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import net.shambolica.ember.jinterface.wrappers.objects.EOPattern;

import java.util.Map;

/**
 * Tuple/String/List length preds.
 */
public class EOPLength extends EOPattern {

    public static final int OP_EQ = 0;
    public static final int OP_LT = 1;
    public static final int OP_GT = 2;

    private final int op;
    private final int value;

    public EOPLength(int op, int value) {
        if (op < OP_EQ || op > OP_GT) {
            throw new IllegalArgumentException("invalid op for length pattern: "+op);
        }
        this.op = op;
        this.value = value;
    }

    @Override
    public Map<String, OtpErlangObject> match(OtpErlangObject term, Map<String, OtpErlangObject> acc) {
        int length;
        if (term instanceof OtpErlangList) {
            length = ((OtpErlangList)term).arity();
        } else if (term instanceof OtpErlangString) {
            length = ((OtpErlangString)term).stringValue().length();
        } else if (term instanceof OtpErlangTuple) {
            length = ((OtpErlangTuple)term).arity();
        } else {
            return null;
        }

        switch (op) {
            case OP_EQ: return length == value ? mkAcc(acc) : null;
            case OP_LT: return length < value ? mkAcc(acc) : null;
            case OP_GT: return length > value ? mkAcc(acc) : null;
            default: throw new Error("can never get here");
        }
    }

    @Override
    public boolean isAbstract() {
        return true;
    }

}
